#ifndef _OBJLOADER_H_
#define _OBJLOADER_H_

#include <list>
#include <fstream>
#include <string>
#include <map>
#include <vector>

#include "imageloader.h"
#include "vec3f.h"
#include "color.h"

/** \brief Represents a material
 *
 * 	Any material which is applied to a 3D model should be
 * 	represented using this class, which allows it to be
 * 	loaded from an MTL file and stores its properties
 * 	as members.
 */
class Material
{
	private:
		std::string _name; /**< Name of Material */
		Vec3f _Ka;	/**< Ambient reflectivity */
		Vec3f _Kd;	/**< Diffuse reflectivity */
		Vec3f _Ks;	/**< Specular reflectivity */
		float _Ns;	/**< Specular exponent */
		unsigned int _texid; /**< Texture ID */
		
	public:
		/** \brief Constructs a Material with the given properties
		 *
		 * 	Constructs a Material with the given properties, typically
		 * 	read in from an MTL file, but can be specified manually as
		 * 	well.
		 *
		 * 	\param name Name of Material
		 * 	\param Ka Ambient reflectivity
		 * 	\param Kd Diffuse reflectivity
		 * 	\param Ks Specular reflectivity
		 * 	\param Ns Specular exponent
		 * 	\param texid Texture ID
		 */
		Material(std::string name, Vec3f Ka, Vec3f Kd, Vec3f Ks, float Ns,
				unsigned int texid);

		/** \brief Name of Material
		 *
		 * 	\return Name of Material
		 */
		std::string name() const;

		/** \brief Switch the current material to this Material
		 *
		 *	Activites this Material as the current active OpenGL material.
		 */
		void useMTL();

		/** \brief Constructs Material from MTL file
		 *
		 * 	Takes an open MTL file and reads the material information into
		 * 	memory. The MTL file must be closed by the caller of this class.
		 *
		 * 	\param file Opened stream to MTL file
		 * 	\param dir Directory with any files called by MTL file (e.g.,
		 * 	BMPs)
		 *
		 * 	\return A vector of all the Material in the \a file.
		 */
		static std::vector<Material> loadMTL(std::ifstream& file, std::string dir);
};

/** \brief Represents a 3D model
 *
 * 	Any 3D model in the game is to be represented using
 * 	this class, which allows it to be loaded and compiled
 * 	into a display list and drawn using Model::draw()
 */
class Model
{
	private:
		unsigned int dlistid;		/**< Display list ID */

		/** \brief Determine facet normal vector of a triangle from the
		 * 	vertex normals and calls \a glNormal3fv().
		 *
		 * 	\param a Normal vector of the first vertex
		 * 	\param a Normal vector of the second vertex
		 * 	\param a Normal vector of the third vertex
		 * 	\param vn Any vertex normal for the triangle
		 *
		 */		 
		 static void normal(Vec3f a, Vec3f b, Vec3f c, Vec3f vn);

		/** \brief Read OBJ format and store into a display list
		 *
		 * 	This function uses an ifstream to read the OBJ file, saving all
		 * 	drawing information into a display list which can be easily 
		 * 	called to draw the entire model.
		 *
		 * 	\param filename OBJ file
		 *
		 */
		void loadVerts(const char* const filename);

	public:
		/** \brief Initialize Model from given OBJ filename.
		 *
		 * 	The OBJ file is expected to be in "../models/<file>".
		 * 	\a filename will typically include a directory, i.e.,
		 * 	"foo/foo001.obj", for convenient grouping of models.
		 *
		 * 	\param filename OBJ filename
		 * 	\param quality Quality of loaded model, 0-2 (low-hi)
		 */
		Model(const char* const filename, unsigned int quality);
		
		/** \brief Draw the display list which holds the model
		 */
		 void draw();
};

#endif
